

#include "server.h"

////////////////////////////////////////////////////////////////////////////////

/**
 * 当有数据可读时，libevent调用这个函数
 */
void
buffered_on_read(struct bufferevent *bev, void *arg)
{
    /* 写回读缓冲区。注意 bufferevent_write_buffer 将逐渐发送完输入的数据
     * 所以我们调用它时，它就开始生效了。 */
    // bufferevent_write_buffer(bev, bev->input);

	struct connect_t *conn = (struct connect_t *)arg;
	int length;

	while((length = evbuffer_get_length(bev->input)) > DEF_HEAD_LENGTH) {
		struct tlv_buf_t headbuf;
		struct proto_head_t proto_head;

    	// 拷贝出协议头,不删除先.
    	evbuffer_copyout(bev->input, headbuf.data, sizeof(proto_head));
    	proto_head_unpack(&headbuf, &proto_head);

		// 协议错误就丢收到的所有数据.
    	if(proto_head.magic != PROTO_MAGIC) {
			evbuffer_drain(bev->input, length);
			return;
		}

		// 收到的够一个完整包.就丢掉协议头,由处理函数处理.
    	if(length >= DEF_HEAD_LENGTH + proto_head.len) {
    		evbuffer_drain(bev->input, DEF_HEAD_LENGTH);

    		struct tlv_buf_t buf;
    		evbuffer_remove(bev->input, buf.data, proto_head.len);
    		buf.len = proto_head.len;
    		buf.pos = buf.data;

    		msg_proc(conn, &proto_head, &buf);
    	}
	}

	return;
}

/**
 * 当写缓冲为0时，libevent调用这个函数。我们写出这个函数只是因为libevent需要，但是我们没有使用它。
 */
void
buffered_on_write(struct bufferevent *bev, void *arg)
{
}

/**
 * 当基础的socket描述符发生错误时，libevent将调用这个函数。
 */
void
buffered_on_error(struct bufferevent *bev, short what, void *arg)
{
    struct connect_t *conn = (struct connect_t *)arg;

    if (what & EVBUFFER_EOF)
    {
        /* 客户端断开连接，在这里移除读事件并释放客户数据结构。 */
        printf("Client disconnected.\n");
    }
    else
    {
        warn("Client socket error, disconnecting.\n");
    }
    bufferevent_free(conn->buf_event);
    close(conn->fd);
    conn->fd = -1;
}

// 当有一个连接请求准备被接受时,这个函数将被libevent调用.
void on_accept(int fd, short ev, void *arg)
{
    int conn_fd;

    // 接受新的连接
    conn_fd = accept_connect(fd);
    if (conn_fd == -1) {
        warn("accept_connect() error\n");
        return;
    }

    // 已经到最大连接值.
    if(conn_fd >= DEF_CLI_MAX) {
        close(conn_fd);
        return;
    }

	struct connect_t *conn = &global.connect[conn_fd];
	conn->type = DEF_SERV_CLIENT;

	fprintf(stderr, "add a client fd %d\n", conn_fd);

    conn->fd = conn_fd;
    conn->buf_event = bufferevent_new(conn_fd, buffered_on_read,
                                     buffered_on_write, buffered_on_error, conn);
	bufferevent_base_set(global.ev_base, conn->buf_event);
    /* 我们必须在回调函数被调用前，使它有效。 */
    bufferevent_enable(conn->buf_event, EV_READ);
}

// 建立监听端口.
int agent_listen()
{
    // 创建监听端口.
    global.listen_fd = create_listen(NULL, g_config.port);
    if(global.listen_fd < 0) {
        err(-1, "create_listen() error\n");
        return -1;
    }

    // 创建一个读事件,当有客户连接时,接收通知.
    global.ev_accept = event_new(global.ev_base, global.listen_fd, EV_TIMEOUT|EV_READ|EV_PERSIST, on_accept, NULL);
    event_add(global.ev_accept, NULL);

    return 0;
}

// 主处理函数
static int run()
{
    int result;

    // 初始化libevent.
    global.ev_base = event_base_new();
    if (!global.ev_base) {
            err(-1, "Could not open event_base\n");
            return -1;
    }

    // 创建本机监听端口.
    result = agent_listen();
    if(result != 0) {
		err(-1, "agent_listen() error\n");
        return -1;
    }

    // 开始 libevent 的事件循环.
    event_base_dispatch(global.ev_base);

    return 0;
}

// 入口.
int main(int argc, char *argv[])
{
    signal(SIGPIPE, SIG_IGN);

    // 读取配置文件.
    read_config();

    // 是否后台进程.
    if(g_config.is_daemon) {
        daemon(0, 0);
    }

	for(int i=0; i<DEF_CLI_MAX; i++) {
		global.connect[i].fd = -1;
	}
	global.connect_count = 0;

    // 启动处理函数.
    run();

    return 0;
}


